/**
 * 
 */
package org.metaverse.warehouse.rdf;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import org.openrdf.model.Literal;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.vocabulary.XMLSchema;

/**
 * @author vjache
 *
 */
public abstract class Converter {
	
	public static final NumberFormat NUM_FORMAT = NumberFormat.getInstance(Locale.US);
	public static final DateFormat ISO8601_UTC = getISO8601DateFormat("GMT");
	public static final SimpleDateFormat ISO8601 = 
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
	
	/**
     * Returns a DateFormat object conforms to ISO-8601 date/time format 
     * (as required by the XML-Schema specification).
     * 
     * <p>The returned format is:
     * <pre>
     * 	yyyy-MM-dd'T'HH:mm:ss.S'Z'
     * </pre>
     * <p>The time will be reduced to the UTC i.e. Zulu time.
     * 
     * @return a DateFormat object
     */
    public static DateFormat getISO8601DateFormat(String aTimeZoneID) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'",Locale.UK);
        //UTC wanted
        sdf.setTimeZone(TimeZone.getTimeZone(aTimeZoneID));
        return sdf;
    }
    
    public static Literal valueOf(Date aDate, ValueFactory aFactory){
    	return aFactory.createLiteral(ISO8601_UTC.format(aDate), XMLSchema.DATETIME);
    }
    public static Literal valueOf(int aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(aValue);
    }
    public static Literal valueOf(long aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(aValue);
    }
    public static Literal valueOf(float aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(aValue);
    }
    public static Literal valueOf(double aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(aValue);
    }
    public static Literal valueOf(byte aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(aValue);
    }
    public static Literal valueOf(short aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(aValue);
    }
    public static Literal valueOf(boolean aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(aValue);
    }
    public static Literal valueOf(String aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(aValue);
    }
    public static Literal valueOf(BigInteger aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(NUM_FORMAT.format(aValue),XMLSchema.INTEGER);
    }
    public static Literal valueOf(BigDecimal aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(NUM_FORMAT.format(aValue),XMLSchema.DECIMAL);
    }
    public static Literal valueOf(java.net.URI aValue, ValueFactory aFactory){
    	return aFactory.createLiteral(aValue.toString(),XMLSchema.ANYURI);
    }
    public static Literal valueOf(Object aValue, ValueFactory aFactory){
    	if(aValue instanceof String)
    		return valueOf((String)aValue,aFactory);
    	else if(aValue instanceof Integer)
    		return valueOf(((Integer)aValue).intValue(),aFactory);
    	else if(aValue instanceof Long)
    		return valueOf(((Long)aValue).longValue(),aFactory);
    	else if(aValue instanceof Double)
    		return valueOf(((Double)aValue).doubleValue(),aFactory);
    	else if(aValue instanceof Float)
    		return valueOf(((Float)aValue).floatValue(),aFactory);
    	else if(aValue instanceof Short)
    		return valueOf(((Short)aValue).shortValue(),aFactory);
    	else if(aValue instanceof Byte)
    		return valueOf(((Byte)aValue).byteValue(),aFactory);
    	else if(aValue instanceof Boolean)
    		return valueOf(((Boolean)aValue).booleanValue(),aFactory);
    	else if(aValue instanceof Date)
    		return valueOf((Date)aValue,aFactory);
    	else if(aValue instanceof BigInteger)
    		return valueOf((BigInteger)aValue,aFactory);
    	else if(aValue instanceof BigDecimal)
    		return valueOf((BigDecimal)aValue,aFactory);
    	else if(aValue instanceof java.net.URI)
    		return valueOf((java.net.URI)aValue,aFactory);
    	
    	throw new UnsupportedOperationException(String.format("Can not take value of %s.", aValue));
    }
    
    @SuppressWarnings("unchecked")
	public static <T> T toJavaValue(Literal aLit){
    	URI datatype = aLit.getDatatype();
    	if(datatype==null)
    		datatype = XMLSchema.STRING;
    	
    	Object value;
    	
    	if(datatype.equals(XMLSchema.STRING))
    	{
    		value = aLit.stringValue();
    	}
    	else if(datatype.equals(XMLSchema.INT))
    	{
    		value = aLit.intValue();
    	}
    	else if(datatype.equals(XMLSchema.INTEGER))
    	{
    		value = aLit.integerValue();
    	}
    	else if(datatype.equals(XMLSchema.FLOAT))
    	{
    		value = aLit.floatValue();
    	}
    	else if(datatype.equals(XMLSchema.DOUBLE))
    	{
    		value = aLit.doubleValue();
    	}
    	else if(datatype.equals(XMLSchema.DATETIME))
    	{
    		try {
				value = ISO8601.parse(aLit.stringValue());
			} catch (ParseException e) {
				try {
					value = ISO8601_UTC.parse(aLit.stringValue());
				} catch (ParseException e1) {
					throw new UnsupportedOperationException(String.format("Only ISO8601 date time format is allowed. Was %s.", aLit));
				}
			}
    	}
    	else if(datatype.equals(XMLSchema.BYTE))
    	{
    		value = aLit.byteValue();
    	}
    	else if(datatype.equals(XMLSchema.SHORT))
    	{
    		value = aLit.shortValue();
    	}
    	else if(datatype.equals(XMLSchema.BOOLEAN))
    	{
    		value = aLit.booleanValue();
    	}
    	else if(datatype.equals(XMLSchema.ANYURI))
    	{
    		value = java.net.URI.create(aLit.stringValue());
    	}
    	else if(datatype.equals(XMLSchema.DECIMAL))
    	{
    		value = aLit.decimalValue();
    	}
    	else
    		throw new UnsupportedOperationException(String.format("Can not convert %s to a primitive Java dtat type.", aLit));
    	return (T)value;
    }
    

}
